package com.mrogrape.gui;

import java.awt.Desktop;
import java.awt.EventQueue;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.net.URI;

import javax.swing.JOptionPane;

import com.mrogrape.util.StringUtils;


/**
 * 一个用于显示链接的Label。
 * 
 * <p>
 * 这个类扩展自ButonLabel，可以用来管理或展示一个链接。链接的格式是URI。因为URL其实
 * 是URI的子类，所以并不提供对URL的直接支持，你可以通过{@link java.net.URL#toURI()}
 * 来将一个URL转化为一个URI。
 * 
 * <p>
 * 虽然此链接的text和uri这两者并无关联，但是基于实际情况，在设置该标签指向的URI时，如果
 * text属性为空（null或空字符串）。那么将默认设置text属性为此URI的字符串表现形式。此
 * 情况在设置URI属性为null时无效。
 * 
 * <p>
 * 此链接标签已经添加了默认的浏览动作，并且默认启用。如果当前设置了URI且有效，那么在
 * 点击此标签时会自动调用系统浏览器浏览此URI。此操作通过{@link java.awt.Desktop#browse(URI)}
 * 实现。如果系统不支持此操作，则会弹出警告对话框。如果需要禁用动作，那么可以将
 * actionEnabled属性设置为false。特殊说明，如果URI描述的是本地的文件，那么可能将会
 * 调用本地资源管理器来打开这个文件或者目录。而不是在浏览器中从事这个操作。这最终将
 * 取决于本地系统的策略。
 * 
 * <p>
 * <b>提示：</b>虽然大部分的Swing方法都不是线程安全的，但此类的所有与访问UI有关的方法都
 * 经过重写以保证其线程安全，注意这不并不包括从父类继承的方法。
 * 
 * 
 * @author Ice Spring
 * @version 1.0.20110831
 */
public class LinkLabel extends ButtonLabel {

	/** SerialVersionUID */
	private static final long serialVersionUID = 1L;

	/**
	 * 创建默认的LinkLabel。默认情况下displayText属性为空字符串，URI属性为null;
	 */
	public LinkLabel(){

		this(null,null);
	}

	/**
	 * 创建LinkLabel并指定显示的文本。
	 * 
	 * @param text 指定显示的文本
	 */
	public LinkLabel(String text){

		this(text,null);
	}

	/**
	 * 根据URI创建LinkLabel对象，对象将以URI的字符串形式作为显示的文本。
	 * 
	 * @param uri 该LinkLabel指向的URI。
	 */
	public LinkLabel(URI uri){

		this(null,uri);
	}

	/**
	 * 创建LinkLabel并指定显示的文本和指向的URI。
	 * 
	 * @param text 显示的文本
	 * @param uri  指向的URI
	 */ 
	public LinkLabel(String text ,URI uri){

		this.setText(text);
		this.setURI(uri);

		this.init();
	}


	/**
	 * 重写以提供线程安全和功能支持。
	 * 
	 * <p>
	 * 特别说明，如果设置此值为空(null或空字符串)，且URI属性不为空，那么将自动设置
	 * 该值为URI属性的字符串表示形式。
	 * 
	 */
	@Override
	public void setText(String text) {

		if(StringUtils.isEmpty(text)&&this.uri!=null){
			this.text = this.uri.toString();
		}else{
			this.text = text;
		}
		this.updateText();
	}

	@Override
	public String getText() {

		return this.text;
	}

	/**
	 * 获取此LinkLabel对应的URI对象。
	 * 
	 * @return 此LinkLabel对应的URI对象。
	 */
	public URI getURI() {

		return this.uri;
	}

	/**
	 * 设置此LinkLabel对应的URI对象。
	 * 
	 * <p>
	 * 如果设置此方法时text属性为空，且设置的URI对象不为空，则会设置text属性为此URI
	 * 对象的字符串表示形式。
	 * 
	 * <p>
	 * 这是一个符合JavaBeans(tm)规范的绑定(bound)属性
	 * 
	 * @param uri 此LinkLabel对应的URI对象。
	 * @see #getURI()
	 */
	public void setURI(URI uri) {

		String text = this.getText();
		if (StringUtils.isEmpty(text) && uri != null) {
			this.setText(uri.toString());
		}

		URI old = this.uri;
		this.uri = uri;
		this.firePropertyChange("URI", old, uri);
	}

	/**
	 * 查看此标签是否已经添加了默认动作。
	 * 
	 * @return 此标签是否已经添加了默认动作的标记：
	 * 			true  : 已经添加了默认动作；
	 * 			false : 没有添加默认动作。
	 */
	public boolean isActionEnabled() {

		return this.actionEnabled;
	}

	/**
	 * 设置是否为此标签添加默认动作。
	 * 
	 * <p>
	 * 添加默认动作后，点击此链接标签时将自动调用系统浏览器打开对应的URI。
	 * 
	 * <p>
	 * 这是一个符合JavaBeans(tm)规范的绑定(bound)属性
	 * 
	 * @param actionEnabled 是否为此标签默认动作的标记：
	 * 						true  : 已经添加了默认动作；
	 * 						false : 没有添加默认动作。
	 */
	public void setActionEnabled(boolean actionEnabled) {

		boolean old = this.actionEnabled;
		this.actionEnabled = actionEnabled;
		this.firePropertyChange("actionEnabled", old, this.actionEnabled);
	}

	private void init(){
		super.setClickFlagEnable(true);
		super.addMouseListener(new BrowseAction());
	}

	private void updateText(){

		EventQueue.invokeLater(new Runnable(){

			@Override
			public void run() {

				LinkLabel.super.setText(LinkLabel.this.text);
			}

		});
	}


	/**
	 * 动作监听器，用以打开LinkLabel对应的URI.
	 * @author Ice Spring
	 *
	 */
	private class BrowseAction extends MouseAdapter {

		@Override
		public void mouseClicked(MouseEvent e) {

			if(LinkLabel.this.uri == null || !LinkLabel.this.actionEnabled){
				return;
			}

			Desktop desktop = Desktop.getDesktop();
			if(desktop.isSupported(Desktop.Action.BROWSE)){
				try {
					desktop.browse(LinkLabel.this.uri);
				} catch (IOException e1) {
					JOptionPane.showMessageDialog(LinkLabel.this,
							"An Exception has occured when browse URI :"
							+ LinkLabel.this.uri.toString(), "I/O Exception",
							JOptionPane.ERROR_MESSAGE);
				}
			} else {
				JOptionPane.showMessageDialog(LinkLabel.this,
						"Your platform not support this action.", "Unsupport",
						JOptionPane.ERROR_MESSAGE);
			}
		}

	}


	//
	// Properties and Local Veriables
	//

	private URI uri = null;
	private String text = null;
	private boolean actionEnabled = true;

}
